package org.black.phoneUtility.sms.reply.app.service;

import java.util.Calendar;

import org.black.phoneUtility.MainActivity;
import org.black.phoneUtility.R;
import org.black.phoneUtility.sms.reply.database.dataModel.SmsReply;
import org.black.phoneUtility.sms.reply.provider.SmsReplyContract;
import org.black.phoneUtility.sms.reply.telephony.ReplyPhoneStateListener;

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.media.AudioManager;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Html;
import android.util.Log;

public class SmsReplyNotificationIntentService extends IntentService {

	public static final String ARGUMENTS_SMS_REPLY_ID = "arguments_sms_reply_id";
	public static final String ARGUMENTS_SMS_REPLY_ACTIVATED = "arguments_sms_reply_activated";
	public static final String ARGUMENTS_SMS_MESSAGE = "arguments_sms_message";
	public static final String ARGUMENTS_SMS_DESTINATION_ADDRESS = "arguments_sms_destination_address";
	public static final String ARGUMENTS_SHOW_NOTIFICATION_ON_STATUS_BAR = "arguments_show_notification_on_status_bar";
	public static final String ARGUMENTS_SHOULD_NOT_CALL_BACK_TO_SCHEDULE_NOTIFY_NOTIFICATION_INTENT_SERVICE = "arguments_should_not_call_back_to_schedule_notify_notification_intent_service";
	public static final String ARGUMENTS_ACTION_TYPE = "arguments_action_type";

	// Notification Id
	private static final int NOTIFICATION_ID_SMS_AUTO_REPLY = 16385;
	private static final String NOTIFICATION_TAG_AUTO_REPLY = "notification_tag_auto_reply";

	public static final int NOTIFICATION_ID_SMS_AUTO_REPLY_SEND_MESSAGE = 16386;
	public static final String NOTIFICATION_TAG_AUTO_REPLY_SEND_MESSAGE = "notification_tag_auto_reply_send_message";

	public static final int ACTION_TYPE_SMS_REPLY_SINGLE = 128;
	public static final int ACTION_TYPE_SMS_REPLY_MESSAGE_BE_SENT = 129;
	public static final int ACTION_TYPE_SMS_REPLY_RECHECK = 130;

	private static final String LOG_TAG = SmsReplyNotificationIntentService.class
			.getName();

	public SmsReplyNotificationIntentService() {
		super(SmsReplyNotificationIntentService.class.getName());
	}

	@Override
	public void onCreate() {
		super.onCreate();
		Log.d(LOG_TAG, "SmsReplyNotificationIntentService create.");
	}

	@Override
	protected void onHandleIntent(Intent intent) {
		int actionType = intent.getIntExtra(ARGUMENTS_ACTION_TYPE, 0);
		if (actionType < ACTION_TYPE_SMS_REPLY_SINGLE
				|| actionType > ACTION_TYPE_SMS_REPLY_RECHECK) {
			Log.e(LOG_TAG,
					"SmsReplyNotificationIntentService Action Type error! Action Type is: "
							+ actionType);
		}
		Log.i(LOG_TAG, "Action Type is: " + actionType);

		SharedPreferences sharedPreferences = PreferenceManager
				.getDefaultSharedPreferences(this);
		final boolean shouldShowNotificationOnStatusBar = sharedPreferences
				.getBoolean(
						getString(R.string.preference_sms_reply_show_notification),
						true);
		boolean shouldShowNotification = false;
		boolean shouldTurnRingerModeSilent = false;
		boolean shouldNotCallScheduleNotificationIntentService = intent
				.getBooleanExtra(
						ARGUMENTS_SHOULD_NOT_CALL_BACK_TO_SCHEDULE_NOTIFY_NOTIFICATION_INTENT_SERVICE,
						false);

		NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
		TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
		Intent resultIntent = new Intent(this, MainActivity.class);
		Bundle resultBundle = new Bundle();
		resultBundle.putInt(MainActivity.ARGUMENTS_DRAWER_SELECT_ITEM,
				MainActivity.DRAWER_SELECT_SMS_REPLY);
		resultIntent.putExtras(resultBundle);
		stackBuilder.addNextIntent(resultIntent);
		PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
				PendingIntent.FLAG_UPDATE_CURRENT);

		Notification.Builder notificationBuilder = new Notification.Builder(
				this)
				.setSmallIcon(R.drawable.sms_reply_notification_icon)
				.setContentTitle(
						getString(R.string.sms_reply_notification_content_title))
				.setOngoing(true).setContentIntent(resultPendingIntent);

		CharSequence contextText = null;
		if (actionType == ACTION_TYPE_SMS_REPLY_RECHECK
				|| actionType == ACTION_TYPE_SMS_REPLY_SINGLE) {
			Cursor cursor = null;
			try {
				cursor = this.getContentResolver().query(
						SmsReplyContract.SmsReplies.CONTENT_URI,
						null,
						SmsReplyContract.SmsReplies.IS_ACTIVATED + " = ? ",
						new String[] { String.valueOf(1) },
						SmsReplyContract.SmsReplies.ACTIVATION_DATE_TIME
								+ " DESC", null);
				if (cursor != null) {
					for (cursor.moveToFirst(); cursor.isAfterLast() == false; cursor
							.moveToNext()) {
						long smsReplyId = cursor
								.getLong(cursor
										.getColumnIndex(SmsReplyContract.SmsReplies._ID));
						boolean checkResult = this
								.checkShouldShowNotification(cursor);
						if (checkResult == true) {
							shouldShowNotification = true;
						}
						if (shouldShowNotification == true) {
							if (shouldTurnRingerModeSilent == false) {
								if (this.checkShouldTurnRingerModeSilentOn(cursor) == true) {
									shouldTurnRingerModeSilent = true;
								}
							}
						}
						if (shouldNotCallScheduleNotificationIntentService == false) {
							this.sendSmsReplyScheduleNotifyService(smsReplyId);
						}
					}
				}
			} catch (Throwable throwable) {
				Log.e(LOG_TAG, "Unknown Error!", throwable);
			} finally {
				if (cursor != null) {
					try {
						cursor.close();
					} catch (Throwable th) {
						Log.e(LOG_TAG,
								"Fail to close cursor for querying SmsReply",
								th);
					}
				}
			}

			if (true == shouldShowNotification) {
				contextText = getString(R.string.sms_reply_notification_content_text_available);
			}

		} else if (actionType == ACTION_TYPE_SMS_REPLY_MESSAGE_BE_SENT) {
			shouldShowNotification = true;
			if (shouldShowNotification == true) {
				Notification.BigTextStyle inboxStyle = new Notification.BigTextStyle();
				String message = intent.getStringExtra(ARGUMENTS_SMS_MESSAGE);
				String destinationAddress = intent
						.getStringExtra(ARGUMENTS_SMS_DESTINATION_ADDRESS);
				contextText = Html
						.fromHtml(String
								.format(getString(R.string.sms_reply_notification_ticker_text_message_has_been_sent),
										destinationAddress, message));
				inboxStyle.setBigContentTitle(destinationAddress);

				inboxStyle.bigText(contextText);
				notificationBuilder
						.setTicker(Html.fromHtml(String
								.format(getString(R.string.sms_reply_notification_ticker_text_message_has_been_sent),
										destinationAddress, message)));
				notificationBuilder.setContentTitle(destinationAddress);
				notificationBuilder.setStyle(inboxStyle);
			}
		} else {
			Log.e(LOG_TAG, "ActionType not mtach. actionType: " + actionType);
			return;
		}

		if (shouldShowNotification == true) {
			sharedPreferences
					.edit()
					.putLong(
							ReplyPhoneStateListener.PREFERENCE_LAST_MISSED_CALL_TIME,
							System.currentTimeMillis()).commit();
		} else {
			notificationManager.cancel(NOTIFICATION_TAG_AUTO_REPLY,
					NOTIFICATION_ID_SMS_AUTO_REPLY);
			sharedPreferences
					.edit()
					.putLong(
							ReplyPhoneStateListener.PREFERENCE_LAST_MISSED_CALL_TIME,
							Long.MIN_VALUE).commit();
		}

		if (shouldShowNotificationOnStatusBar == true) {
			if (shouldShowNotification == true) {
				notificationBuilder.setContentText(contextText);
				Notification notification = notificationBuilder.build();
				if (actionType == ACTION_TYPE_SMS_REPLY_MESSAGE_BE_SENT) {
				} else {
					notification.flags = Notification.FLAG_NO_CLEAR;
					notificationManager.notify(NOTIFICATION_TAG_AUTO_REPLY,
							NOTIFICATION_ID_SMS_AUTO_REPLY, notification);
				}
			} else {
				notificationManager.cancel(NOTIFICATION_TAG_AUTO_REPLY,
						NOTIFICATION_ID_SMS_AUTO_REPLY);
			}
		} else {
			notificationManager.cancel(NOTIFICATION_TAG_AUTO_REPLY,
					NOTIFICATION_ID_SMS_AUTO_REPLY);
		}

		AudioManager audioManager = (AudioManager) this
				.getSystemService(Context.AUDIO_SERVICE);
		String originalRingerKey = getString(R.string.preference_sms_reply_original_ringer_mode);
		if (shouldTurnRingerModeSilent == true) {
			if (sharedPreferences.contains(originalRingerKey) == false) {
				sharedPreferences
						.edit()
						.putInt(originalRingerKey, audioManager.getRingerMode())
						.commit();
				audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
			}
		} else {
			if (sharedPreferences.contains(originalRingerKey) == true) {
				int originalMode = sharedPreferences.getInt(originalRingerKey,
						AudioManager.RINGER_MODE_NORMAL);
				audioManager.setRingerMode(originalMode);
				sharedPreferences.edit().remove(originalRingerKey).commit();
			}
		}
	}

	private boolean checkShouldShowNotification(Cursor cursor) {
		boolean result = false;
		int replyDateTimeModeType = cursor
				.getInt(cursor
						.getColumnIndex(SmsReplyContract.SmsReplies.REPLY_DATE_TIME_TYPE));
		long currentTimeInMilliSeconds = System.currentTimeMillis();
		if (replyDateTimeModeType == SmsReply.REPLY_DATE_TIME_MODE_ALWAYS_TYPE) {
			result = true;
		} else if (replyDateTimeModeType == SmsReply.REPLY_DATE_TIME_MODE_PERIOD_TYPE) {
			long periodStartTime = cursor
					.getLong(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.PERIOD_START_DATE_TIME));
			long periodEndTime = cursor
					.getLong(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.PERIOD_END_DATE_TIME));
			if (currentTimeInMilliSeconds >= periodStartTime
					&& currentTimeInMilliSeconds < periodEndTime) {
				result = true;
			}
		} else if (replyDateTimeModeType == SmsReply.REPLY_DATE_TIME_MODE_EXPIRED_AFTER_TYPE) {
			long activationTime = cursor
					.getLong(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.ACTIVATION_DATE_TIME));
			long expiredAfterMilliseconds = cursor
					.getLong(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.EXPIRATED_AFTER_MILLISECONDS));
			if (currentTimeInMilliSeconds >= activationTime
					&& currentTimeInMilliSeconds < activationTime
							+ expiredAfterMilliseconds) {
				result = true;
			}
		} else if (replyDateTimeModeType == SmsReply.REPLY_DATE_TIME_MODE_REPEAT_TYPE) {
			Calendar currentCalendar = Calendar.getInstance();

			int currentHour = currentCalendar.get(Calendar.HOUR_OF_DAY);
			int currentMinute = currentCalendar.get(Calendar.MINUTE);

			Calendar startCalendar = Calendar.getInstance();
			startCalendar
					.setTimeInMillis(cursor.getLong(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.REPEAT_START_TIME)));
			Calendar endCalendar = Calendar.getInstance();
			endCalendar
					.setTimeInMillis(cursor.getLong(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.REPEAT_END_TIME)));
			if (endCalendar.getTimeInMillis() <= startCalendar
					.getTimeInMillis()) {
				endCalendar.add(Calendar.DAY_OF_YEAR, 1);
			}

			int startHour = startCalendar.get(Calendar.HOUR_OF_DAY);
			int startMinute = startCalendar.get(Calendar.MINUTE);

			int endHour = endCalendar.get(Calendar.HOUR_OF_DAY);
			int endMinute = endCalendar.get(Calendar.MINUTE);

			if (startHour * 60 + startMinute >= endHour * 60 + endMinute) {
				endHour += 24;
			}
			int currentTimeInMinutes = currentHour * 60 + currentMinute;
			int startTimeInMinutes = startHour * 60 + startMinute;
			int endTimeInMinutes = endHour * 60 + endMinute;
			if (currentTimeInMinutes >= startTimeInMinutes
					&& currentTimeInMinutes < endTimeInMinutes) {
				result = true;
			}
			boolean isSundayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_SUNDAY_ENABLE)) == 1 ? true
					: false;
			boolean isMondayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_MONDAY_ENABLE)) == 1 ? true
					: false;
			boolean isTuesdayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_TUESDAY_ENABLE)) == 1 ? true
					: false;
			boolean isWednesdayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_WEDNESDAY_ENABLE)) == 1 ? true
					: false;
			boolean isThursdayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_THURSDAY_ENABLE)) == 1 ? true
					: false;
			boolean isFridayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_FRIDAY_ENABLE)) == 1 ? true
					: false;
			boolean isSaturdayEnable = cursor
					.getInt(cursor
							.getColumnIndex(SmsReplyContract.SmsReplies.IS_SATURDAY_ENABLE)) == 1 ? true
					: false;

			if ((isSundayEnable == true || isMondayEnable == true
					|| isTuesdayEnable == true || isWednesdayEnable == true
					|| isThursdayEnable == true || isFridayEnable == true || isSaturdayEnable == true)
					&& result == true) {
				int dayOfWeek = currentCalendar.get(Calendar.DAY_OF_WEEK);
				switch (dayOfWeek) {
				case Calendar.SUNDAY:
					if (isSundayEnable == false) {
						result = false;
					}
					break;
				case Calendar.MONDAY:
					if (isMondayEnable == false) {
						result = false;
					}
					break;
				case Calendar.TUESDAY:
					if (isTuesdayEnable == false) {
						result = false;
					}
					break;
				case Calendar.WEDNESDAY:
					if (isWednesdayEnable == false) {
						result = false;
					}
					break;
				case Calendar.THURSDAY:
					if (isThursdayEnable == false) {
						result = false;
					}
					break;
				case Calendar.FRIDAY:
					if (isFridayEnable == false) {
						result = false;
					}
					break;
				case Calendar.SATURDAY:
					if (isSaturdayEnable == false) {
						result = false;
					}
					break;
				default:
					Log.e(LOG_TAG, "dayOfWeek: " + dayOfWeek
							+ " is incorrect! Seriously Error!");
					result = false;
					break;
				}
			}
		} else {
			Log.e(LOG_TAG, "Something wrong on reply date time mode! "
					+ SmsReplyContract.SmsReplies.REPLY_DATE_TIME_TYPE + ": "
					+ replyDateTimeModeType);
		}
		return result;
	}

	private boolean checkShouldTurnRingerModeSilentOn(Cursor cursor) {
		return 1 == cursor
				.getInt(cursor
						.getColumnIndexOrThrow(SmsReplyContract.SmsReplies.ENABLE_RINGER_MODE_SILENT)) ? true
				: false;
	}

	private void sendSmsReplyScheduleNotifyService(long smsReplyId) {
		Intent scheduleNotifyNotificationServiceIntent = new Intent(this,
				SmsReplyScheduleNotifyNotificationInentService.class);
		Bundle argumentsForSchedule = new Bundle();
		argumentsForSchedule
				.putInt(SmsReplyScheduleNotifyNotificationInentService.ARGUMENTS_ACTION_TYPE,
						SmsReplyScheduleNotifyNotificationInentService.ACTION_TYPE_SCHEDULE_SPECIFIC_SMS_REPLY);
		argumentsForSchedule
				.putLong(
						SmsReplyScheduleNotifyNotificationInentService.ARGUMENTS_SMS_REPLY_ID,
						smsReplyId);
		scheduleNotifyNotificationServiceIntent.putExtras(argumentsForSchedule);
		startService(scheduleNotifyNotificationServiceIntent);
		Log.d(LOG_TAG, "Start SmsReplyScheduleNotifyNotificationInentService!");
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		Log.d(LOG_TAG, "SmsReplyNotificationIntentService destory.");
	}

}
